import { I, M, K, KI, C } from "./combinators/combinators1.mjs";
import { B, TH, V, BL } from "./combinators/combinators2.mjs";
import { True, False, and, not } from "./boolean-logic.mjs";

Function.prototype.toJsNum = function() {
  return this(x => x + 1)(0);
};

const zero = KI;

//const succ = n => f => a => f(n(f)(a));
const succ = n => f => B(f)(n(f));

const one = succ(zero);
const two = succ(one);
const three = succ(two);
const four = succ(three);
const five = succ(four);

console.log("Numbers");
console.log(zero.toJsNum());
console.log(one.toJsNum());
console.log(two.toJsNum());
console.log(three.toJsNum());
console.log(four.toJsNum());
console.log(five.toJsNum());

const add = n => k => n(succ)(k);
const add1 = n => n(succ);
console.log("Addition1");
console.log(add1(one)(one).toJsNum());
console.log(add1(three)(five).toJsNum());

console.log("Addition");
console.log(add(one)(one).toJsNum());
console.log(add(three)(five).toJsNum());

const mult = B;

console.log("Multiplication");
console.log(mult(two)(two).toJsNum());
console.log(mult(three)(five).toJsNum());

const pow = TH;

console.log("Exponentiation");
console.log(pow(two)(two).toJsNum());
console.log(pow(three)(four).toJsNum());

const isZero = n => n(K(False))(True);

console.log("Is Zero");
console.log(isZero(zero).toJsBool());
console.log(isZero(one).toJsBool());
console.log(isZero(three).toJsBool());

const pair = V;
const fst = a => a(K);
const snd = a => a(KI);

const myPair = pair(one)(three);

console.log("Pair");
console.log(fst(myPair).toJsNum());
console.log(snd(myPair).toJsNum());

const phi = p => V(snd(p))(succ(snd(p)));

console.log(fst(pair(one)(two)).toJsNum());

const pred = n => fst(n(phi)(pair(zero)(zero)));

console.log("Pred");
console.log(pred(two).toJsNum());
console.log(pred(five).toJsNum());

const subtract = n => k => k(pred)(n);

console.log("Subtract");
console.log(subtract(two)(one).toJsNum());
console.log(subtract(five)(two).toJsNum());
console.log(subtract(five)(zero).toJsNum());

const lessThanOrEquals = n => k => isZero(subtract(n)(k));

console.log("Less than or equals");
console.log(lessThanOrEquals(two)(one).toJsBool());
console.log(lessThanOrEquals(one)(three).toJsBool());
console.log(lessThanOrEquals(one)(one).toJsBool());

const greaterThanOrEquals = C(lessThanOrEquals);

console.log("Greater than or equals");
console.log(greaterThanOrEquals(two)(one).toJsBool());
console.log(greaterThanOrEquals(one)(three).toJsBool());
console.log(greaterThanOrEquals(one)(one).toJsBool());

const greaterThan = BL(not)(lessThanOrEquals);

console.log("Greater than");
console.log(greaterThan(two)(one).toJsBool());
console.log(greaterThan(one)(three).toJsBool());
console.log(greaterThan(one)(one).toJsBool());

const lessThan = BL(not)(greaterThanOrEquals);

console.log("Less than");
console.log(lessThan(two)(one).toJsBool());
console.log(lessThan(one)(three).toJsBool());
console.log(lessThan(one)(one).toJsBool());

const equals = n => k => and(lessThanOrEquals(n)(k))(lessThanOrEquals(k)(n));

console.log("Equality");
console.log(equals(two)(one).toJsBool());
console.log(equals(one)(three).toJsBool());
console.log(equals(one)(one).toJsBool());


